#include "circulos.h"

circulos::circulos(const QList<Point>& vertices, const QList<triangulo>& triangulos)
{
    // Para cada triangulo "t", pegar os seus 3 vértices e calcular o centro e o raio do círculo formado por eles:
    foreach (const triangulo& t,triangulos) lista_circulos.append(calcularCentroRaio(vertices[t.a],vertices[t.b],vertices[t.c]));
}

const QList<circulo>& circulos::getCirculos() const
{
    return(lista_circulos);
}

void circulos::imprimir(const double mat[3][3]) const
{
    for (int i=0 ; i<3 ; i++)
    {
        for (int j=0 ; j<3 ; j++) cout<<mat[i][j]<<"\t";
        cout<<endl;
    }
}

double circulos::determinanteSarrus(const double mat[3][3]) const
{
    return(mat[0][0]*mat[1][1]*mat[2][2]
         + mat[0][1]*mat[1][2]*mat[2][0]
         + mat[0][2]*mat[1][0]*mat[2][1]
         - mat[0][2]*mat[1][1]*mat[2][0]
         - mat[1][2]*mat[2][1]*mat[0][0]
         - mat[2][2]*mat[0][1]*mat[1][0]);
}

circulo circulos::calcularCentroRaio(const Point& p1, const Point& p2, const Point& p3)
{
    // Checar se os Pontos são de, pelo menos, dimensão 2 (plano);
    // Se pelo menos um deles não o for, o raio recebe o valor "-1":
    if ((p1.get_dimensao() < 2) || (p2.get_dimensao() < 2) || (p3.get_dimensao() < 2)) return(circulo(0.0,0.0,-1.0));

    double matriz_aux[3][3];

    // Determinante "a":
    matriz_aux[0][0] = p1(0);
    matriz_aux[0][1] = p1(1);
    matriz_aux[0][2] = 1;
    matriz_aux[1][0] = p2(0);
    matriz_aux[1][1] = p2(1);
    matriz_aux[1][2] = 1;
    matriz_aux[2][0] = p3(0);
    matriz_aux[2][1] = p3(1);
    matriz_aux[2][2] = 1;
    double a = determinanteSarrus(matriz_aux);
    //cout<<"Matriz A:"<<endl;imprimir(matriz_aux);

    // Checar se os 3 pontos são colineares.
    // Caso sejam, o raio recebe o valor "-1":
    if (fabs(a) <= 0.000000001) return(circulo(0.0,0.0,-1.0));

    // Determinante "d":
    matriz_aux[0][0] = pow(p1(0),2) + pow(p1(1),2);
    matriz_aux[1][0] = pow(p2(0),2) + pow(p2(1),2);
    matriz_aux[2][0] = pow(p3(0),2) + pow(p3(1),2);
    double d = -determinanteSarrus(matriz_aux);
    //cout<<"Matriz D:"<<endl;imprimir(matriz_aux);

    // Determinante "e":
    matriz_aux[0][1] = p1(0);
    matriz_aux[1][1] = p2(0);
    matriz_aux[2][1] = p3(0);
    double e = determinanteSarrus(matriz_aux);
    //cout<<"Matriz E:"<<endl;imprimir(matriz_aux);

    // Determinante "f":
    matriz_aux[0][2] = p1(1);
    matriz_aux[1][2] = p2(1);
    matriz_aux[2][2] = p3(1);
    double f = -determinanteSarrus(matriz_aux);
    //cout<<"Matriz F:"<<endl;imprimir(matriz_aux);

    double Cx   = -(d/(2*a));
    double Cy   = -(e/(2*a));
    double raio = sqrt(((pow(d,2) + pow(e,2))/(4*pow(a,2))) - (f/a));

    /*
    cout<<"a  = "<<a<<endl;
    cout<<"d  = "<<d<<endl;
    cout<<"e  = "<<e<<endl;
    cout<<"f  = "<<f<<endl;
    cout<<"Cx = "<<Cx<<endl;
    cout<<"Cy = "<<Cy<<endl;
    cout<<"r  = "<<raio<<endl;
    */

    return(circulo(Cx,Cy,raio));
}

void circulos::desenhaCirculo(double x, double y, double raio)
{
    // Cor e tamanho da linha:
    glColor3f(0.5,0.5,0.5);
    glLineWidth(1.0);
    double y1 = y + raio;
    double x1 = x;
    glBegin(GL_LINE_STRIP);
    for (double angle=0.0f ; angle<=(2.0f*M_PI) ; angle+=0.01f)
    {
        double x2 = x + (raio*(double)sin((double)angle));
        double y2 = y + (raio*(double)cos((double)angle));
        glVertex2d(x1,y1);
        y1 = y2;
        x1 = x2;
    }
    glEnd();
}

void circulos::draw()
{
    cout<<"*** LISTA DE CIRCULOS ***"<<endl;
    foreach (const circulo& c,lista_circulos)
	{
        cout<<"+ circulo("<<c.x<<" , "<<c.y<<" , "<<c.r<<")"<<endl;
        if (c.r != -1.0) desenhaCirculo(c.x,c.y,c.r);
	}
}
